package module

import (
	"bufio"
	"fmt"
	"my_im2/server/_interface"
	"net"
	"sync"
)

type CommunicationModule struct {
	ip            string
	port          int
	server        _interface.Server
	idCount       uint
	idCountLock   sync.Mutex
	idConnMap     map[uint]net.Conn
	idConnMapLock sync.RWMutex
}

func NewCommunicationModule(ip string, port int, server _interface.Server) *CommunicationModule {
	c := &CommunicationModule{
		ip:        ip,
		port:      port,
		server:    server,
		idCount:   0,
		idConnMap: make(map[uint]net.Conn),
	}
	return c
}

func (c *CommunicationModule) Start() {
	//socket listen
	listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", c.ip, c.port))
	if err != nil {
		c.server.GetLogger().LogError("listen err:", err)
		return
	}

	//close listen socket
	defer listener.Close()

	//循环监听accept
	for {
		conn, err := listener.Accept()
		if err != nil {
			c.server.GetLogger().LogError("listener accept err:", err)
			continue
		}

		go c.handleConn(conn)
	}
}

func (c *CommunicationModule) nextId() uint {
	c.idCountLock.Lock()
	defer c.idCountLock.Unlock()
	c.idCount++
	return c.idCount
}

// 处理每个客户端连接
func (c *CommunicationModule) handleConn(conn net.Conn) {
	//生成id
	id := c.nextId()

	c.server.GetLogger().LogInfo(fmt.Sprintf("[建立连接] (%d) 服务端=%v，客户端=%v", id, conn.LocalAddr(), conn.RemoteAddr()))

	//向服务器注册conn id
	c.server.GetDb().AddConn(id)

	//自己也注册id
	c.addConn(id, conn)

	//接收客户端发送的消息
	scanner := bufio.NewScanner(conn)
	for scanner.Scan() {
		msg := scanner.Text()
		//调用服务器方法
		c.server.GetBusiness().HandleMsg(id, msg)
	}

	//如果断开连接，则视为下线
	c.server.OnDisconnect(id)
	c.server.GetLogger().LogInfo(fmt.Sprintf("[断开连接] (%d) 服务端=%v，客户端=%v", id, conn.LocalAddr(), conn.RemoteAddr()))
}

func (c *CommunicationModule) addConn(id uint, conn net.Conn) {
	c.idConnMapLock.Lock()
	defer c.idConnMapLock.Unlock()
	c.idConnMap[id] = conn
}

func (c *CommunicationModule) SendMsg(id uint, msg string) {
	c.idConnMapLock.RLock()
	defer c.idConnMapLock.RUnlock()
	conn, ok := c.idConnMap[id]
	if ok {
		conn.Write([]byte(msg + "\n")) //以换行分隔消息
	}
}
